package cn.bitkit.assist.counter;

import cn.bitkit.tools.common.NumberUtil;
import cn.bitkit.tools.common.ThreadUtil;
import cn.bitkit.tools.data.JSONUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.LongAdder;
import java.util.stream.IntStream;

/**
 * @author changbo
 */
@Slf4j
public class QpsCounter {

    public static void run(List<Integer> list, int total, BaseRunner runner){
        System.out.println("init start");
        runner.init();
        System.out.println("init end");
        List<CountValue> countList = new ArrayList<>();
        LongAdder index = new LongAdder();
        list.forEach(thread -> {
            try {
                run(runner, thread, countList, total, index);
            } catch (Exception e) {
                log.error("", e);
            }
        });
        System.out.println(JSONUtil.toJsonFormat(countList));
    }

    public static void run(BaseRunner runner, int thread, List<CountValue> countList, int total, LongAdder index) throws Exception{
        long start = System.currentTimeMillis();
        ThreadFactory factory = Thread.ofVirtual().factory();
        LongAdder finish = new LongAdder();
        LongAdder success = new LongAdder();
        LongAdder allTime = new LongAdder();
        Semaphore semaphore = new Semaphore(thread);
        IntStream.range(0, total).forEach(i -> {
            try {
                semaphore.acquire();
            } catch (Exception e) {
                log.error("", e);
            }
            Thread virtualThread = factory.newThread(() -> {
                long start1 = System.currentTimeMillis();
                boolean res = false;
                try {
                    res = runner.execute(index.intValue());
                } catch (Exception e) {
                    log.error("", e);
                }
                long end1 = System.currentTimeMillis();
                long time1 = end1 - start1;
                allTime.add(time1);
                if(res){
                    success.increment();
                }
                index.increment();
                finish.increment();
                semaphore.release();
            });
            virtualThread.start();
        });
        //等待全部完成
        int len = 0;
        do{
            ThreadUtil.sleep(100);
            len = semaphore.availablePermits();
        }while (len != thread);
        long end = System.currentTimeMillis();
        long time = end - start;
        countList.add(CountValue.builder()
                .thread(thread)
                .total(total)
                .success(success.intValue())
                .fail(total - success.intValue())
                .totalTime(time)
                .avgTime(allTime.longValue()/total)
                .qps(NumberUtil.setScale(total/(time/1000.0), 2))
                .build());
        System.out.println("执行:" + thread + "->" + time + "ms");
    }

}
